package service

import (
	sqlc "bgs/db/sqlc"
	"bgs/cache/redisImp"
	"bgs/conf"
	"bgs/db"
	"bgs/grpc/client"
	"bgs/grpc/gen/proxy2/account"
	"bgs/grpc/imp/enums"
	"bgs/util"
	"context"
	"encoding/json"
	"fmt"
	"go.uber.org/zap"
	"time"
)

// BrandServiceImp brand bizlogic
type BrandServiceImp struct {
	dao    *db.PgDao
	slog   *zap.SugaredLogger
	wechatVars *conf.WechatSection
	vars   *conf.VarsSection
	proxy  *client.GrpcClientProxy
	cacher *cache.Adapter
}

// NewBrandService initialization
func NewBrandService(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	wechatVars *conf.WechatSection,
	vars *conf.VarsSection,
	proxy *client.GrpcClientProxy,
	adp *cache.Adapter,
) *BrandServiceImp {
	return &BrandServiceImp{
		dao:    pgdao,
		slog:   slog.With("module", "BrandService"),
		wechatVars: wechatVars,
		vars:   vars,
		proxy:  proxy,
		cacher: adp,
	}
}

type genWebposTokenRet struct {
	ID           string `json:"id,omitempty"`
	ErrorCode    string `json:"error_code,omitempty"`
	ErrorMessage string `json:"error_message,omitempty"`
}

// FetchBrandWebposTokenSafely 安全确保拿到token
func (s *BrandServiceImp) FetchBrandWebposTokenSafely(ctx context.Context, q *sqlc.Queries, brandID int64) (token string, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	cBrand := s.cacher.FetchBrand(brandID)
	if cBrand == nil {
		err = fmt.Errorf("not found brand of brandID:%d", brandID)
		return
	}

	token = cBrand.Ext.WebposToken

	// WebposToken 14天过期,提早一天刷新
	if time.Now().Unix()-cBrand.Ext.WebposTokenRefreshedTS > 13*86400 || token == "" {
		slog.Infof("WebposToken 14天过期或者不存在,提早一天刷新")
		ownUser, sqlErr := q.GetUser(ctx, cBrand.Ext.OwnUserID)
		if sqlErr != nil {
			err = sqlErr
			return
		}
		memberToken := ownUser.MemberToken.String

		uri := fmt.Sprintf("%s/web/v3/account/employee-cookie", s.vars.WebposURI)
		param := map[string]interface{}{
			"sg_id": cBrand.SgID,
		}
		headers := map[string]string{
			"auth": memberToken,
		}
		ctxWithTimout, cancel := context.WithTimeout(ctx, util.Uint8ToSecondDuration(s.vars.HTTPTimeout))
		defer cancel()

		body, httpErr := util.GetRequest().Send(ctxWithTimout, "POST", uri, param, headers, 1)
		if httpErr != nil {
			err = httpErr
			return
		}

		resp := &genWebposTokenRet{}
		if err = json.Unmarshal(body, resp); err != nil {
			return
		}
		if resp.ErrorCode == "SSO_TOKEN_NOT_FOUND" {
			// sso token 过期
			slog.Infof("sso token 过期 获取最新的sso token后再次获取")

			mobile := ownUser.Mobile.String
			email := ""
			app := string(enums.APPIDBGS)
			nonce := ownUser.OpenID
			secret := s.vars.AccountSecret

			raw := fmt.Sprintf("%s%s%s%s%s", mobile, email, app, nonce, secret)
			sign, signErr := util.SignSha256(raw)
			if signErr != nil {
				err = signErr
				return
			}
			req := &account.CredibleLoginReq{
				Mobile: ownUser.Mobile.String,
				App:    string(enums.APPIDBGS),
				Nonce:  ownUser.OpenID,
				Email:  email,
				Sign:   sign,
			}

			ctxWithTimout2, cancel2 := s.proxy.NewContextWith(ctx)
			defer cancel2()

			reply, grpcErr := s.proxy.AccountCl.CredibleLogin(ctxWithTimout2, req)
			if grpcErr != nil {
				err = grpcErr
				return
			}
			slog.Infof("sso token 生成 ok ")

			memberToken = reply.Token

			_, err = q.UpdateUserMemberToken(ctx, sqlc.UpdateUserMemberTokenParams{
				ID:          ownUser.ID,
				MemberToken: sqlc.NSFromString(memberToken),
			})
			if err != nil {
				return
			}
			slog.Infof("user unique token 更新 ok ")

			headers["auth"] = memberToken

			ctxWithTimout3, cancel3 := context.WithTimeout(ctx, util.Uint8ToSecondDuration(s.vars.HTTPTimeout))
			defer cancel3()
			body, httpErr = util.GetRequest().Send(ctxWithTimout3, "POST", uri, param, headers, 1)
			if httpErr != nil {
				err = httpErr
				return
			}

			if err = json.Unmarshal(body, resp); err != nil {
				return
			}
		}
		token = resp.ID

		_, err = q.UpdateBrandExtWebposInfoByBrandID(ctx, sqlc.UpdateBrandExtWebposInfoByBrandIDParams{
			BrandID:              brandID,
			WebposToken:          sqlc.NSFromString(token),
			WebposTokenRefreshed: time.Now(),
		})

		s.cacher.UnsetBrand(brandID)
	}

	slog.Infof("webpos token:%s", token)

	return
}


// ClearCache 清空当前品牌缓存
func (s *BrandServiceImp) ClearCache(brandID int64) {
	s.cacher.UnsetBrand(brandID)
}